home *** CD-ROM | disk | FTP | other *** search
/ HyperLib 1997 Winter - Disc 1 / HYPERLIB-1997-Winter-CD1.ISO.7z / HYPERLIB-1997-Winter-CD1.ISO / オンラインウェア / PRG / Mac_F2C_1.3.2.sit / Mac F2C 1.3.2 / Mac F2C v1.3.2 Documentation.rsrc / TEXT_141.txt < prev    next >
Text File  |  1996-10-18  |  8KB  |  155 lines

  1. When Translated Code Won窶冲 Run
  2.  
  3.  
  4. It is not unusual for code produced by Mac F2C to compile without any problems, but crash and burn when run.  In fact, if you get to the ccommand() dialog (the one that asks you to set up standard input and standard output), but crash immediately there after, it is almost certain that you are blowing out the stack space.  The problem and its solution are described below.
  5.  
  6. The problem arises because FORTRAN allocates memory for all its variables statically.  The C code produced by Mac F2C by default uses automatic storage for most variables.  On the Macintosh automatic variables get stored on the stack.  When the FORTRAN code declares large arrays (quite common in FORTRAN code), these become large arrays on the stack in the C version.  Because less than 24K is normally allocated as stack space by default on the Macintosh, your program blows out the stack.
  7.  
  8. There are two 窶徠uick窶 fixes to this problem which usually work (either separately or in combination).  There is also a more tedious, but 100% reliable fix that involves modifying the code generated by Mac F2C.  All three of these fixes are described below.
  9.  
  10.  
  11. Quick Fix 1:  Use Static Storage
  12.  
  13. The first quick fix to try is to translate the FORTRAN code with the Make local variables automatic vice static option in the C Output options dialog unchecked.  This will move all of the large arrays from the stack to the global data space.  You should also increase the memory partition for your program (either in the Finder窶冱 Get Info dialog if it is a free-standing application, or in the appropriate THINK, Symantec, or CodeWarrior dialog if it is under development) to allow for the extra memory required by the large global arrays.
  14.  
  15. This 窶彷ix窶 will often solve the problem.  However, because some C/C++ compilers still impose a 32K limit on the amount of global data per file, you can still have problems with files that have too many large arrays in them.  If you are lucky, you can divide the file somehow so that the arrays are split among several files and now don窶冲 violate the 32K/file limit.  However, that might not be possible if, for example, all the arrays appear within a single subroutine.  If not, try 窶弉uick Fix 2窶 or the 窶弋rue but Tedious Fix窶 described below.
  16.  
  17.  
  18. Quick Fix 2:  Enlarge the Stack
  19.  
  20. Both F2CMain.c and F2CMain.cp contain code that adjusts the size of the stack when generating 68K code.  You can simply modify a single line in these files to adjust the stack size to whatever you need.  
  21.  
  22. If you are generating PPC code, then you can set the stack size to anything you need by modifying the PEF, but I don窶冲 have a PowerMac, so I don窶冲 know how you would do this.  Sorry.
  23.  
  24. To change the stack size when generating 68K code, open either F2CMain.c or F2CMain.cp, as appropriate, and search for the following segement of code:
  25.  
  26. #define kDesiredStackSize  (40*1024L)     /* 68K stack size set to 40K bytes */
  27. #if GENERATING68K && defined(kDesiredStackSize)    
  28.       if ( kDesiredStackSize > LMGetDefltStack() )
  29.       {
  30.         Ptr newApplLimit = 
  31.                            GetApplLimit() - (kDesiredStackSize - LMGetDefltStack());
  32.             SetApplLimit( newApplLimit );
  33.       }
  34. #endif    /* increase stack size */
  35.  
  36. The key line is the one that defines kDesiredStackSize.  It is currently set to 40KB.  If you want to make the stack 200KB, simply edit the line, changing the 40 to 200, so the line now reads:
  37.  
  38. #define kDesiredStackSize  (200*1024L)     /* 68K stack size set to 200K bytes */
  39.  
  40. After making the change, simply rebuild your executable and give it a try.  It窶冱 hard to determine the correct stack size.  You can scan your source code and add up the size of the big arrays to get a rough estimate.  In any case, some trial-and-error will be required.  If you increase the stack size significantly, remember also to increase the memory partition for your program by a corresponding amount.
  41.  
  42. The 窶彿ncrease the stack size窶 fix should generally work.  If it doesn窶冲, you can modify the code generated by Mac F2C to move the memory allocations from the stack to the heap (i.e., from automatic to dynamic allocation).  How to do this is described in the next section.
  43.  
  44.  
  45. True but Tedious Fix:  Allocate Memory Dynamically
  46.  
  47. If all else fails, the only solution is to edit the C code so that it allocates the memory dynamically.
  48.  
  49. Let窶冱 work an example.  Consider the following simple FORTRAN program:
  50.  
  51.     program example
  52.     
  53.     double precision d
  54.     dimension a(100,100), b(100,200,20)
  55.     dimension d(50,20,10)
  56.     
  57.     a(100,100) = 1.0
  58.     b(100,200,20) = 1.0
  59.     d(50,20,10) = 1.0d0
  60.     
  61.     stop
  62.     end
  63.  
  64. Basically all it does is allocate three arrays.  Note that the arrays are not that large by FORTRAN standards.  Selecting the option that allocates local variables automatically, this program translates into:
  65.  
  66. /* JUNK.f -- translated by f2c (version 19941113).
  67.    You must link the resulting object file with the libraries:
  68.     -lf2c -lm   (in that order)
  69. */
  70.  
  71. #include "f2c.h"
  72.  
  73. /* Main program */ MAIN__(void)
  74. {
  75.     /* Builtin functions */
  76.     /* Subroutine */ int s_stop(char *, ftnlen);
  77.  
  78.     /* Local variables */
  79.     real a[10000]   /* was [100][100] */, b[400000] /* was [100][200][20] 
  80.         */;
  81.     doublereal d[10000] /* was [50][20][10] */;
  82.  
  83.     a[9999] = 1.f;
  84.     b[399999] = 1.f;
  85.     d[9999] = 1.;
  86.     s_stop("", 0L);
  87.     return 0;
  88. } /* MAIN__ */
  89.  
  90. /* Main program alias */ int example_ () { MAIN__ (); return 0; }
  91.  
  92.  
  93. Note how in the C version 410,000 reals and 10,000 doublereals are allocated on the stack窶杯hat窶冱 over 1.5MB on the stack.  Your program will crash the moment it enters the MAIN__() function.  If you tried using static vice automatic variables you would have over 32K of global data in one file and it wouldn窶冲 build under THINK C.  
  94.  
  95. Multi-dimensional arrays can be quite large even when their individual dimensions are small.  It窶冱 easy to blow out the stack or the THINK C limit on global data per file with even one or two arrays of three or more dimensions.  I窶况e also seen programs get into problems because they have lots of small arrays.
  96.  
  97. The solution is to replace the array variables with pointers and allocate the memory for them using malloc() or any of its cousins.  Because C treats pointers and arrays similarly, the rest of the code works without any changes. 
  98.  
  99. Applying this technique to the example yields the following modified code:
  100.  
  101. /* JUNK.f -- translated by f2c (version 19941113).
  102.    You must link the resulting object file with the libraries:
  103.     -lf2c -lm   (in that order)
  104. */
  105.  
  106. #include "f2c.h"
  107.  
  108. #define NEW_CODE            /* <========  to make the changes clear */
  109.  
  110. #ifdef NEW_CODE
  111. #include <stdlib.h>         /* Get prototypes for malloc(), etc */
  112. #endif
  113.  
  114. /* Main program */ MAIN__(void)
  115. {
  116.     /* Builtin functions */
  117.     /* Subroutine */ int s_stop(char *, ftnlen);
  118.  
  119.     /* Local variables */
  120. #ifdef NEW_CODE 
  121.     real        *a, *b;         /* Pointers instead of arrays */
  122.     doublereal  *d;         
  123. #else
  124.     real a[10000]   /* was [100][100] */, b[400000] /* was [100][200][20] 
  125.         */;
  126.     doublereal d[10000] /* was [50][20][10] */;
  127. #endif
  128.  
  129.  
  130. #ifdef NEW_CODE                                 /* allocate the memory */
  131.     a = (real *) malloc( 10000*sizeof(real) );
  132.     b = (real *) malloc( 400000*sizeof(real) );
  133.     d = (doublereal *) malloc( 10000*sizeof(doublereal) );
  134.     /* Remember to check a, b, and d for NULL (e.g., out of memory) */
  135. #endif
  136.  
  137.     a[9999] = 1.f;
  138.     b[399999] = 1.f;
  139.     d[9999] = 1.;
  140.     
  141. #ifdef NEW_CODE
  142.     free( a );          /* Don't forget to free the memory */
  143.     free( b );
  144.     free( d );
  145. #endif
  146.  
  147.     s_stop("", 0L);
  148.     return 0;
  149. } /* MAIN__ */
  150.  
  151. /* Main program alias */ int example_ () { MAIN__ (); return 0; }
  152.  
  153. This version of the program will work fine so long as there is enough heap space to allocate the memory requested in the malloc() calls.  You can add more heap space by simply increasing the partition size of the program (either in the Finder窶冱 Get Info dialog if it is a free-standing application, or in the appropriate THINK, Symantec, or CodeWarrior dialog if the code is under development).
  154.  
  155. This modified version will also work if the variables a, b, and d had been declared static vice automatic.